package com.qf.mprefer.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qf.mprefer.ex.QFException;
import com.qf.mprefer.user.controller.UsersController;
import com.qf.mprefer.user.entity.User;
import com.qf.mprefer.user.mapper.UsersMapper;
import com.qf.mprefer.user.service.IUsersService;
import com.qf.mprefer.user.shiro.ShiroConstants;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.UUID;

/**
 * <p>
 * 用户  服务实现类
 * </p>
 *
 * @author dong_
 * @since 2022-11-03
 */
@Service
public class UsersServiceImpl extends ServiceImpl<UsersMapper, User> implements IUsersService {

    @Autowired
    RedisTemplate redisTemplate;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public User regist(User user) {

       //1. 比对密码是否一致
       final String password = user.getPassword();
       final String repassword = user.getRepassword();
       if ( !(password!=null&&password.equals(repassword)) ){
           // 密码有问题，两次密码不一致
           throw new QFException("密码有问题，两次密码不一致");
       }
        //2.比对验证码是否一致
        String realRandomNumbers = (String) redisTemplate.opsForValue().get(user.getPhone());

        if (!(user.getRandomNumbers()!=null&&user.getRandomNumbers().equals(realRandomNumbers))){
            //验证码有问题,与收到的验证码不一致
            throw new QFException("验证码有问题,与收到的验证码不一致");
        }

        //3. 检查用户名是否存在
//        final User dbUser = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, user.getUsername()));
        final User dbUser = this.getOne(new QueryWrapper<User>().eq("username",user.getUsername()));
        if (dbUser!=null){
            throw new QFException("用户名重复了");
        }

        //4. 生成salt，对密码进行加密处理
        final String salt = UUID.randomUUID().toString().replaceAll("-", "");
        final Md5Hash md5Hash = new Md5Hash(password, salt, ShiroConstants.HASH_TIMES);
        final String shiroPassword = md5Hash.toHex();

        //5. 保存用户数据到数据库
        user.setSalt(salt);
        user.setPassword(shiroPassword);

        user.setUserRegtime(new Date());
        user.setUserModtime(new Date());

        this.save(user);

        return user;
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public User loginBySend(User user) {
        String phone = user.getPhone();

        String realRandomNumbers = (String)redisTemplate.opsForValue().get(phone);
        if(!(user.getRandomNumbers().equals(realRandomNumbers))){
            throw new QFException("手机号或验证码错误");
        }
        User phoneUser = this.getOne(new QueryWrapper<User>().eq("phone", phone));

        return phoneUser;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveUserToRedis(User user) {

        redisTemplate.opsForValue().set(user.getUsername(), JSON.toJSONString(user));

    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public User selectUserByUsername(User user) {

        return getOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, user.getUsername()));

    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public User modifyUser(User user) {
        boolean update = this.update(user, new QueryWrapper<User>().eq("user_id", user.getUserId()));
        if(update){
            User updateUser = this.getOne(new QueryWrapper<User>().eq("user_id", user.getUserId()));
            return updateUser;
        }else{
            return null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User modifyPassword(Integer userId, String oldPassword, String newPassword) {
        //1.根据userId查用户
        User dbUser = this.getOne(new QueryWrapper<User>().eq("user_id", userId));
        //2. 获取 shiro 的 subject 对象 进行密码比较
        final Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new UsernamePasswordToken(dbUser.getPhone(),oldPassword));
        } catch (AuthenticationException e) {
            throw new QFException("用户名或者密码错误");
        }
        //3.如果密码匹配,则修改新密码
        User newUser = new User();
        final String salt = UUID.randomUUID().toString().replaceAll("-", "");
        final Md5Hash md5Hash = new Md5Hash(newPassword, salt, ShiroConstants.HASH_TIMES);
        final String shiroNewPassword = md5Hash.toHex();
        newUser.setPassword(shiroNewPassword);
        boolean update = this.update(newUser, new QueryWrapper<User>().eq("user_id", userId));
        if(update){
            User updatePwdUser = this.getOne(new QueryWrapper<User>().eq("user_id", userId));
            return updatePwdUser;
        }else{
            return null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User modifyPhone(Integer userId, String oldPhone, String newPhone) {
        //1.根据userId查用户
        User dbUser = this.getOne(new QueryWrapper<User>().eq("user_id", userId));
        //2.把传过来的原手机与库中的原手机做比对
        String dbUserPhone = dbUser.getPhone();
        if (!(oldPhone!=null&&dbUserPhone.equals(oldPhone))){
            throw new QFException("与原手机号不匹配");
        }
        //3.如果手机号匹配,测试新手机能否收到验证码?
//        String RandomNumbers = (String)redisTemplate.opsForValue().get(newPhone);
        if (!(newPhone!=null&&(String)redisTemplate.opsForValue().get(newPhone)!=null)){
            throw new QFException("你输入的新手机号不正确");
        }
        //4.如果新手机号能收到验证码,则修改手机号
        User newPhoneUser = new User();
        newPhoneUser.setPhone(newPhone);
        boolean update = this.update(newPhoneUser, new QueryWrapper<User>().eq("user_id", userId));
        if(update){
            User updatePhoneUser = this.getOne(new QueryWrapper<User>().eq("user_id", userId));
            return updatePhoneUser;
        }else{
            return null;
        }

    }

}
